use core::{alloc::AllocError, ffi::c_void, marker::PhantomData, ptr::NonNull};

use uefi_ffi::EfiStatus;

use crate::BootServices;

use super::MemoryType;

pub struct Pool<MT: MemoryType> {
    pub raw: NonNull<c_void>,
    phantom: PhantomData<MT>,
}
impl<MT: MemoryType> Pool<MT> {
    pub fn alloc(size: usize) -> Result<Self, AllocError> {
        let pool_type = MT::MEM_TYPE;
        let buffer: NonNull<c_void> = NonNull::dangling();
        if BootServices::take()
            .allocate_pool(pool_type, size, &mut buffer.as_ptr())
            .is_sucess()
        {
            Ok(Self {
                raw: buffer,
                phantom: PhantomData,
            })
        } else {
            Err(AllocError)
        }
    }
    pub fn free(self) {
        if let EfiStatus::InvalidParameter = BootServices::take().free_pool(self.raw.as_ptr()) {
            // @TODO 打印日志。日志系统。
        }
    }
    pub fn as_ptr<T>(&self) -> *mut T {
        self.raw.as_ptr() as *mut T
    }
    pub unsafe fn from_raw(raw: *mut u8) -> Option<Self> {
        Some(Self {
            raw: NonNull::new(raw.cast())?,
            phantom: PhantomData,
        })
    }
}
